home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / gnu / glibc108.gz / glibc108 / glibc-1.08.1 / io / ftw.c < prev    next >
C/C++ Source or Header  |  1994-01-06  |  4KB  |  217 lines

  1. /* Copyright (C) 1992 Free Software Foundation, Inc.
  2. This file is part of the GNU C Library.
  3. Contributed by Ian Lance Taylor (ian@airs.com).
  4.  
  5. The GNU C Library is free software; you can redistribute it and/or
  6. modify it under the terms of the GNU Library General Public License as
  7. published by the Free Software Foundation; either version 2 of the
  8. License, or (at your option) any later version.
  9.  
  10. The GNU C Library is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13. Library General Public License for more details.
  14.  
  15. You should have received a copy of the GNU Library General Public
  16. License along with the GNU C Library; see the file COPYING.LIB.  If
  17. not, write to the Free Software Foundation, Inc., 675 Mass Ave,
  18. Cambridge, MA 02139, USA.  */
  19.  
  20. #include <ansidecl.h>
  21. #include <errno.h>
  22. #include <limits.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25. #include <dirent.h>
  26. #include <sys/types.h>
  27. #include <sys/stat.h>
  28. #include <ftw.h>
  29.  
  30.  
  31. #ifndef PATH_MAX
  32. #define PATH_MAX 1024        /* XXX */
  33. #endif
  34.  
  35.  
  36. /* Traverse one level of a directory tree.  */
  37.  
  38. static int
  39. DEFUN (ftw_dir, (dirs, level, descriptors, dir, len, func),
  40.        DIR **dirs AND int level AND int descriptors AND
  41.        char *dir AND size_t len AND
  42.        int EXFUN((*func), (CONST char *file, struct stat *status,
  43.                int flag)))
  44. {
  45.   int got;
  46.   struct dirent *entry;
  47.  
  48.   got = 0;
  49.  
  50.   errno = 0;
  51.  
  52.   while ((entry = readdir (dirs[level])) != NULL)
  53.     {
  54.       struct stat s;
  55.       int flag, ret, newlev;
  56.  
  57.       ++got;
  58.  
  59.       if (entry->d_name[0] == '.'
  60.       && (entry->d_namlen == 1 ||
  61.           (entry->d_namlen == 2 && entry->d_name[1] == '.')))
  62.     {
  63.       errno = 0;
  64.       continue;
  65.     }
  66.  
  67.       if (entry->d_namlen + len + 1 > PATH_MAX)
  68.     {
  69. #ifdef ENAMETOOLONG
  70.       errno = ENAMETOOLONG;
  71. #else
  72.       errno = ENOMEM;
  73. #endif
  74.       return -1;
  75.     }
  76.  
  77.       dir[len] = '/';
  78.       memcpy ((PTR) (dir + len + 1), (PTR) entry->d_name,
  79.           entry->d_namlen + 1);
  80.  
  81.       if (stat (dir, &s) < 0)
  82.     {
  83.       if (errno != EACCES)
  84.         return -1;
  85.       flag = FTW_NS;
  86.     }
  87.       else if (S_ISDIR (s.st_mode))
  88.     {
  89.       newlev = (level + 1) % descriptors;
  90.  
  91.       if (dirs[newlev] != NULL)
  92.         closedir (dirs[newlev]);
  93.  
  94.       dirs[newlev] = opendir (dir);
  95.       if (dirs[newlev] != NULL)
  96.         flag = FTW_D;
  97.       else
  98.         {
  99.           if (errno != EACCES)
  100.         return -1;
  101.           flag = FTW_DNR;
  102.         }
  103.     }
  104.       else
  105.     flag = FTW_F;
  106.  
  107.       ret = (*func) (dir, &s, flag);
  108.  
  109.       if (flag == FTW_D)
  110.     {
  111.       if (ret == 0)
  112.         ret = ftw_dir (dirs, newlev, descriptors, dir,
  113.                entry->d_namlen + len + 1, func);
  114.       if (dirs[newlev] != NULL)
  115.         {
  116.           int save;
  117.  
  118.           save = errno;
  119.           closedir (dirs[newlev]);
  120.           errno = save;
  121.           dirs[newlev] = NULL;
  122.         }
  123.     }
  124.  
  125.       if (ret != 0)
  126.     return ret;
  127.  
  128.       if (dirs[level] == NULL)
  129.     {
  130.       int skip;
  131.  
  132.       dir[len] = '\0';
  133.       dirs[level] = opendir (dir);
  134.       if (dirs[level] == NULL)
  135.         return -1;
  136.       skip = got;
  137.       while (skip-- != 0)
  138.         {
  139.           errno = 0;
  140.           if (readdir (dirs[level]) == NULL)
  141.         return errno == 0 ? 0 : -1;
  142.         }
  143.     }
  144.  
  145.       errno = 0;
  146.     }
  147.  
  148.   return errno == 0 ? 0 : -1;
  149. }
  150.  
  151. /* Call a function on every element in a directory tree.  */
  152.  
  153. int
  154. DEFUN(ftw, (dir, func, descriptors),
  155.       CONST char *dir AND
  156.       int EXFUN((*func), (CONST char *file, struct stat *status,
  157.               int flag)) AND
  158.       int descriptors)
  159. {
  160.   DIR **dirs;
  161.   size_t len;
  162.   char buf[PATH_MAX + 1];
  163.   struct stat s;
  164.   int flag, ret;
  165.   int i;
  166.  
  167.   if (descriptors <= 0)
  168.     descriptors = 1;
  169.  
  170.   dirs = (DIR **) __alloca (descriptors * sizeof (DIR *));
  171.   i = descriptors;
  172.   while (i-- > 0)
  173.     dirs[i] = NULL;
  174.  
  175.   if (stat (dir, &s) < 0)
  176.     {
  177.       if (errno != EACCES)
  178.     return -1;
  179.       flag = FTW_NS;
  180.     }
  181.   else if (S_ISDIR (s.st_mode))
  182.     {
  183.       dirs[0] = opendir (dir);
  184.       if (dirs[0] != NULL)
  185.     flag = FTW_D;
  186.       else
  187.     {
  188.       if (errno != EACCES)
  189.         return -1;
  190.       flag = FTW_DNR;
  191.     }
  192.     }
  193.   else
  194.     flag = FTW_F;
  195.  
  196.   len = strlen (dir);
  197.   memcpy ((PTR) buf, (PTR) dir, len + 1);
  198.  
  199.   ret = (*func) (buf, &s, flag);
  200.  
  201.   if (flag == FTW_D)
  202.     {
  203.       if (ret == 0)
  204.     ret = ftw_dir (dirs, 0, descriptors, buf, len, func);
  205.       if (dirs[0] != NULL)
  206.     {
  207.       int save;
  208.  
  209.       save = errno;
  210.       closedir (dirs[0]);
  211.       errno = save;
  212.     }
  213.     }
  214.  
  215.   return ret;
  216. }
  217.